package com.luhe.midi;

import com.luhe.midi.helper.MIDIFileLogWriter;
import com.luhe.midi.mthd.MThd;
import com.luhe.midi.mtrk.MTrk;
import org.apache.log4j.Logger;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/*
 * 表示一个midi文件
 * Midi工具类
 * byte范围：-128~127
 * midi格式：4d 54 68 64 00 00 00 06 ff ff nn nn dd dd
 * ff ff轨道:00 00 单轨道
 *          00 01 同步多轨道
 *          00 02 不同步多轨道
 * nn nn 轨道个数，为实际轨道个数+1个全局音轨
 * dd dd 基本时间类型
 */
public class MidiFile {

    //日志
    Logger logger = Logger.getLogger(this.getClass().getName());


    //头部
    private MThd mThd;

    //轨道
    private List<MTrk> mTrkList = new ArrayList<MTrk>();


    public MidiFile() {
    }

    //增加轨道
    public void addMTrk(MTrk mTrk) {
        mTrkList.add(mTrk);
    }

    public MidiFile(MThd mThd, List<MTrk> mTrkList) {
        this.mThd = mThd;
        this.mTrkList = mTrkList;

    }

    public MThd getmThd() {
        return mThd;
    }

    public void setmThd(MThd mThd) {
        this.mThd = mThd;
    }

    public List<MTrk> getmTrkList() {
        return mTrkList;
    }

    public void setmTrkList(List<MTrk> mTrkList) {
        this.mTrkList = mTrkList;
    }

    //写与midi等价csv调试文本格式
    public void writeCSV(Writer writer) throws IOException {
        new MIDIFileLogWriter(this).write(writer);
    }


    //写出MIDI格式数据到文件
    public void write(OutputStream outputStream) throws Exception {
        long t = System.currentTimeMillis();
        logger.info("开始写出midi数据...");
        MThd mThd = this.getmThd();
        mThd.writeOutputStream(outputStream);
        for (MTrk mtrk : this.getmTrkList()) {
            mtrk.writeOutputStream(outputStream);
        }
        logger.info("写出成功！" + (System.currentTimeMillis() - t) + "ms");
    }

    //读MIDI文件数据
    public MidiFile read(InputStream inputStream) throws Exception {
        long t = System.currentTimeMillis();
        logger.info("开始读midi数据...");

        //读头部
        this.readMThd(inputStream);
        logger.info("读入头部成功！");

        //读轨道
        this.readMtrkList(inputStream);
        logger.info("所有轨道读取完毕！" + (System.currentTimeMillis() - t) + "ms");
        return this;

    }

    //读轨道输入流数据
    private List<MTrk> readMtrkList(InputStream inputStream) throws Exception {
        logger.info("开始读入轨道");
        int mtrkNum = this.mThd.mtrkNum;
        this.mTrkList = new LinkedList<>();
        for (int i = 0; i <= mtrkNum - 1; i = i + 1) {
            MTrk mTrk = new MTrk().read(inputStream);
            this.mTrkList.add(mTrk);
        }
        return this.mTrkList;
    }

    //读头部
    private void readMThd(InputStream inputStream) throws Exception {

        this.mThd = new MThd().read(inputStream);


    }


}
